﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace Sworm
{
    public class UpdateOptions<TRoot>
    {
        private readonly TableData table;
        private readonly HashSet<ColumnData> columns = new HashSet<ColumnData>();
        private bool? include; // true for Include, false for Exclude

        public UpdateOptions(TableData table)
        {
            this.table = table;
        }

        private void SetInclusionMode(bool include)
        {
            if (this.include.HasValue && this.include != include)
            {
                throw new InvalidOperationException(
                    "cannot mix Include() and Exclude() calls");
            }
            this.include = include;
        }

        private void AddColumns(string[] columns)
        {
            foreach (string column in columns)
            {
                this.columns.Add(table.RequireColumn(column));
            }
        }

        private void AddColumns(Expression<Func<TRoot, object>>[] columns)
        {
            foreach (var column in columns)
            {
                this.columns.Add(table.RequireColumn(column));
            }
        }

        public UpdateOptions<TRoot> Exclude(params string[] columns)
        {
            SetInclusionMode(false);
            AddColumns(columns);
            return this;
        }

        public UpdateOptions<TRoot> Exclude(params Expression<Func<TRoot, object>>[] columns)
        {
            SetInclusionMode(false);
            AddColumns(columns);
            return this;
        }

        public UpdateOptions<TRoot> Include(params string[] columns)
        {
            SetInclusionMode(true);
            AddColumns(columns);
            return this;
        }

        public UpdateOptions<TRoot> Include(params Expression<Func<TRoot, object>>[] columns)
        {
            SetInclusionMode(true);
            AddColumns(columns);
            return this;
        }

        internal bool IsIncluded(ColumnData column)
        {
            if (include == null)
            {
                return true;
            }
            else if (include.Value)
            {
                return columns.Contains(column);
            }
            else
            {
                return !columns.Contains(column);
            }
        }
    }
}
